#include <jni.h>
#include <string>
#include "Log.h"

#include <sstream>
#include <unistd.h>

extern "C"{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include "../../../thirdParty/fftools/cmdutils.h"
#include "../../../thirdParty/fftools/ffmpeg.h"
    //不改名字 部分手机 JniInvocation: JniInvocation instance already initialized
//int main(int argc, char **argv);
int run(int argc, char **argv);
}


extern "C"
JNIEXPORT jint JNICALL
Java_com_pg_ffmpeg_RecodeUtil_runCommand(JNIEnv *env, jobject thiz, jint argc, jobjectArray args) {
    //初始化 onError 方法反射信息
//    jclass clazz = env->GetObjectClass(thiz);
//    jmethodID progressId = env->GetMethodID(clazz,"onProgress", "(J)V");
//    jmethodID completeId = env->GetMethodID(clazz,"onComplete", "()V");
//    jmethodID failId = env->GetMethodID(clazz,"onFail", "()V");
//    env->CallVoidMethod(thiz, progressId, 12L);
//    env->CallVoidMethod(thiz,completeId);
//    env->CallVoidMethod(thiz,failId);
//    env->NewGlobalRef(thiz);

    char *argCmd[argc] ;
    jstring buf[argc];
    for (int i = 0; i < argc; ++i) {
        buf[i] = static_cast<jstring>(env->GetObjectArrayElement(args, i));
        char *string = const_cast<char *>(env->GetStringUTFChars(buf[i], JNI_FALSE));
        argCmd[i] = string;
        Log("argCmd=%s",argCmd[i]);
    }
    Log("开始main ");
    int retCode = run(argc, argCmd);
    Log("ffmpeg-invoke: retCode=%d",retCode);

    return retCode;
}

extern "C"
JNIEXPORT jstring JNICALL
Java_com_pg_ffmpeg_RecodeUtil_stringFromJNI(JNIEnv *env, jobject thiz) {
    return env->NewStringUTF(avcodec_configuration());
}

extern "C"
JNIEXPORT jstring JNICALL
Java_com_pg_ffmpeg_RecodeUtil_retrieveInfo(JNIEnv *env, jclass clazz, jstring _path) {
    const char* path=env->GetStringUTFChars(_path, JNI_FALSE);
    AVFormatContext* ctx = nullptr;
    av_register_all();
    avcodec_register_all();
    int ret = avformat_open_input(&ctx, path, nullptr, nullptr);
    if (ret != 0) {
        Log("avformat_open_input() open failed! path:%s, err:%s", path, av_err2str(ret));
        return nullptr;
    }
    ret = avformat_find_stream_info(ctx, nullptr);
    if (ret < 0){
        Log("avformat_find_stream_info() open failed! path:%s, err:%s", path, av_err2str(ret));
        return nullptr;
    }
    env->ReleaseStringUTFChars(_path,path);
    int nStreams = ctx->nb_streams;
    AVStream **pStream = ctx->streams;
    AVStream *vStream = nullptr;
    for (int i = 0; i < nStreams; i++) {
        if (pStream[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
            vStream = pStream[i];
        }
    }
    int width = 0;
    int height = 0;
    int rotation = 0;
    long fps = 0;
    char *vCodecName = nullptr;
    if(vStream!=nullptr){
        width = vStream->codecpar->width;
        height = vStream->codecpar->height;
        rotation = static_cast<int>(get_rotation(vStream));
        int num = vStream->avg_frame_rate.num;
        int den = vStream->avg_frame_rate.den;
        if (den > 0) {
            fps = lround(num * 1.0 / den);
        }
        const char *codecName = avcodec_get_name(vStream->codecpar->codec_id);
        vCodecName = const_cast<char *>(codecName);
    }
    long bitrate = ctx->bit_rate;
    long duration = ctx->duration / 1000;//ms
    avformat_close_input(&ctx);
    std::ostringstream buffer;
    buffer << "{\"rotation\":"<<rotation<<",\"width\":"<<width<<",\"height\":"<<height<<",\"duration\":"<<duration<<",\"bitrate\":"<< bitrate<<",\"fps\":"<<fps<<R"(,"videoCodec":")"<<vCodecName<<"\"}";
    std::string result = buffer.str();
    return env->NewStringUTF(result.c_str());
}
extern "C"
JNIEXPORT jdouble JNICALL
Java_com_pg_ffmpeg_RecodeUtil_getProgress(JNIEnv *env, jobject thiz) {
    return progress();
}extern "C"
JNIEXPORT jint JNICALL
Java_com_pg_ffmpeg_RecodeUtil_getState(JNIEnv *env, jobject thiz) {
    return state;
}
extern "C"
JNIEXPORT jstring JNICALL
Java_com_pg_ffmpeg_RecodeUtil_getErrorInfo(JNIEnv *env, jobject thiz) {
    return env->NewStringUTF(errorMessage);
}